/****************************************************************************
**
** Copyright (C) 1992-2009 Nokia. All rights reserved.
**
** This file is part of Qt Jambi.
**
** $BEGIN_LICENSE$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
** $END_LICENSE$

**
** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
**
****************************************************************************/

package com.trolltech.tools.ant;

import java.io.File;

import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.PropertyHelper;
import org.apache.tools.ant.Task;

public abstract class AbstractInitializeTask extends Task {

    private int verboseLevel;

    private boolean configurationViaSetter;
    private String configuration;

    private boolean test;

    protected PropertyHelper propertyHelper;


    public void execute() throws BuildException {
        propertyHelper = PropertyHelper.getPropertyHelper(getProject());
        executeInitialize();
    }

    abstract void executeInitialize() throws BuildException;


    public int getVerboseLevel() {
        return verboseLevel;
    }

    public void setVerbose(String verboseLevelString) {
        if("true".compareToIgnoreCase(verboseLevelString) == 0) {
            verboseLevel = 1;
            return;
        } if("false".compareToIgnoreCase(verboseLevelString) == 0) {
            verboseLevel = 0;
            return;
        }

        Integer i = Integer.valueOf(verboseLevelString);
        this.verboseLevel = i.intValue();
    }


    // package accessible
    protected String mySetProperty(int verboseMode, String attrName, String sourceValue, String newValue, boolean forceNewValue) throws BuildException {
        String currentValue = AntUtil.getPropertyAsString(propertyHelper, attrName);
        if(newValue != null) {
            if(currentValue != null) {
                String s;
                if(currentValue.equals(newValue))
                    s = " (already set to same value)";
                else
                    s = " (already set; detected as: " + newValue + ")";
                if(sourceValue != null)
                    sourceValue += s;
                else
                    sourceValue = s;
                // Don't error if we don't have to i.e. the two values are the same
                if(forceNewValue && newValue.equals(currentValue) == false)
                    throw new BuildException("Unable to overwrite property " + attrName + " with value " + newValue + " (current value is: " + currentValue + ")");
            } else {
                if(forceNewValue)
                    AntUtil.setProperty(propertyHelper, attrName, newValue, false);
                else
                    AntUtil.setNewProperty(propertyHelper, attrName, newValue);
                currentValue = newValue;
            }
        } else {
            if(currentValue != null)
                sourceValue = null;  // we don't use newValue in any way, and currentValue exists
        }

        if(sourceValue == null)
            sourceValue = "";

        if((verboseMode == -1 && verboseLevel > 0) || (verboseMode > 0)) {
            String prettyCurrentValue = prettyValue(currentValue);
            getProject().log(this, attrName + ": " + prettyCurrentValue + sourceValue, Project.MSG_INFO);
        }

        return currentValue;
    }

    protected String prettyValue(String s) {
        if(s == null)
            s = "<notset>";
        else if(s.length() == 0)
            s = "<empty-string>";
        return s;
    }

    /**
     * Convert "/tmp/somdir/qt/lib/libQtCore.so.4" into "$QTDIR/lib/libQtCore.so.4"
     * @param s
     * @param qtdir  We expect this to have been validated and have any trailing pathSeparator removed.
     * @return
     */
    protected String prettyPathValue(String s, String qtdir) {
        if(s == null) {
            s = "<notset>";
        } else if(s.length() == 0) {
            s = "<empty-string>";
        } else if(qtdir != null) {
            if(s.startsWith(qtdir))
                return "$QTDIR" + s.substring(qtdir.length());
        }
        return s;
    }


    protected String decideJavaHomeTarget() {
        String sourceValue = null;
        String s = AntUtil.getPropertyAsString(propertyHelper, Constants.JAVA_HOME_TARGET);
        if(s == null) {
            try {
                s = System.getenv("JAVA_HOME_TARGET");
                if(s != null)
                    sourceValue = " (from envvar:JAVA_HOME_TARGET)";
            } catch(SecurityException eat) {
            }
        }
        if(s == null) {
            try {
                s = System.getenv("JAVA_HOME");
                if(s != null)
                    sourceValue = " (from envvar:JAVA_HOME)";
            } catch(SecurityException eat) {
            }
        }
        String result = s;
        mySetProperty(-1, Constants.JAVA_HOME_TARGET, sourceValue, result, false);
        return result;
    }

    protected String decideJavaOsarchTarget() {
        String sourceValue = null;
        String s = AntUtil.getPropertyAsString(propertyHelper, Constants.JAVA_OSARCH_TARGET);

        if(s == null) {
            try {
                s = System.getenv("JAVA_OSARCH_TARGET");
                if(s != null)
                    sourceValue = " (from envvar:JAVA_OSARCH_TARGET)";
            } catch(SecurityException eat) {
            }
        }

        if(s == null) {    // auto-detect using what we find
            // This is based on a token observation that the include directory
            //  only had one sub-directory (this is needed for jni_md.h).
            String javaHomeTarget = AntUtil.getPropertyAsString(propertyHelper, Constants.JAVA_HOME_TARGET);
            if(javaHomeTarget != null) {
                File includeDir = new File(javaHomeTarget, "include");
                File found = null;
                int foundCount = 0;

                if(includeDir.exists()) {
                    File[] listFiles = includeDir.listFiles();
                    for(File f : listFiles) {
                        if(f.isDirectory()) {
                            foundCount++;
                            found = f;
                        }
                    }
                }

                if(foundCount == 1) {
                    s = found.getName();
                    sourceValue = " (auto-detected)";
                }
            }
        }

        String result = s;
        mySetProperty(-1, Constants.JAVA_OSARCH_TARGET, sourceValue, result, false);
        return result;
    }

    protected String decideJavaOscpu() {
        String sourceValue = null;
        String s = AntUtil.getPropertyAsString(propertyHelper, Constants.JAVA_OSCPU);

        if(s == null) {
            try {
                s = System.getenv("JAVA_OSCPU");
                if(s != null)
                    sourceValue = " (from envvar:JAVA_OSCPU)";
            } catch(SecurityException eat) {
            }
        }
        if(s == null) {
            try {
                s = System.getProperty("os.arch");
                if(s != null)
                    sourceValue = " (detected from JVM property:os.arch)";
            } catch(SecurityException eat) {
            }
        }

        String result = s;
        mySetProperty(-1, Constants.JAVA_OSCPU, sourceValue, result, false);
        return result;
    }

    protected String decideJavaOscpuTarget() {
        String sourceValue = null;
        String s = AntUtil.getPropertyAsString(propertyHelper, Constants.JAVA_OSCPU_TARGET);

        if(s == null) {
            try {
                s = System.getenv("JAVA_OSCPU_TARGET");
                if(s != null)
                    sourceValue = " (from envvar:JAVA_OSCPU_TARGET)";
            } catch(SecurityException eat) {
            }
        }
        if(s == null) {
            s = AntUtil.getPropertyAsString(propertyHelper, Constants.JAVA_OSCPU);
            if(s != null)
                sourceValue = " (inherited from ${" + Constants.JAVA_OSCPU + "})";
        }
        if(s == null) {
            try {
                s = System.getProperty("os.arch");
                if(s != null)
                    sourceValue = " (detected from JVM property:os.arch)";
            } catch(SecurityException eat) {
            }
        }

        String result = s;
        mySetProperty(-1, Constants.JAVA_OSCPU_TARGET, sourceValue, result, false);
        return result;
    }

    /**
     * Decides whether to use debug or release configuration
     *
     * @return string "debug" or "release" according config resolution
     */
    protected String decideConfiguration() {
        String c = getConfiguration();
        if(c == null) {
            // FIXME perform auto-detect (look at Qt SDK kind)
            throw new BuildException("invalid value for 'configuration' it has not been set");
        }
        return c;
    }

    protected void setConfigurationInternal(String configuration) {
        this.configuration = configuration;
    }
    public void setConfiguration(String configuration) {
        if(Constants.CONFIG_DEBUG.equals(configuration) || Constants.CONFIG_RELEASE.equals(configuration) ||
         Constants.CONFIG_TEST.equals(configuration) || Constants.CONFIG_DEBUG_AND_RELEASE.equals(configuration)) {
            this.configurationViaSetter = true;
            setConfigurationInternal(configuration);
            return;
        }
        throw new BuildException("invalid value for 'configuration' of '" + prettyValue(configuration) + "' allowed settings 'debug', 'release', 'test', 'debug_and_release'");
    }
    public String getConfiguration() {
        return configuration;
    }
    protected boolean isConfigurationViaSetter() {
        return configurationViaSetter;
    }
    protected boolean isConfigurationDebug() {
        return Constants.CONFIG_DEBUG.equals(configuration);
    }
    protected boolean isConfigurationTest() {
        return Constants.CONFIG_TEST.equals(configuration);
    }
    protected boolean isConfigurationDebugAndRelease() {
        return Constants.CONFIG_DEBUG_AND_RELEASE.equals(configuration);
    }

    public void setTest(boolean test) {
        this.test = test;
    }
    protected boolean getTest() {
        return test;
    }
}
